#pragma once
#include <unordered_map>
#include "Epoller.hpp"
#include "Connection.hpp"


#define TIME_OUT 1000
#define MAX_EVENTS 64

class Reactor
{
public:
    Reactor() : _epoller(new Epoller), _max_events(MAX_EVENTS), _isrunning(false), _timeout(TIME_OUT)
    {
        _epoller->InitEpoll();
    }
    ~Reactor()
    {}

    bool IsConnectionExists(int fd)
    {
        auto it = _connections.find(fd);
        if(it == _connections.end()) 
            return false;
        return true;
    }
    void AddConnection(Connection *conn)
    {
        if(!conn) 
            return;
        if(IsConnectionExists(conn->Sockfd())) 
            return;
        // 1. 向_connections中添加conn
        _connections[conn->Sockfd()] = conn;
        // 2. 向_epoller中添加conn关心的事件
        _epoller->AddEvent(conn->Sockfd(), conn->Events());
        ILOG("添加新Connection成功, fd: %d", conn->Sockfd());
    }
    void DelConnection(Connection *conn)
    {
        if(!conn)
            return;
        if(!IsConnectionExists(conn->Sockfd()))
            return;
        int fd = conn->Sockfd();
        // 1. 取消epoll对fd事件的关心
        _epoller->DelEvent(fd);
        // 2. 从_connections中删除conn
        _connections.erase(fd);
        // 3. close fd
        close(fd);
        // 4. 释放空间
        delete conn;
    }
    void SetEvents(int fd, bool in, bool out)
    {
        if(!IsConnectionExists(fd))
            return;
        uint32_t events = EPOLLET | (in == true ? EPOLLIN : 0) | (out == true ? EPOLLOUT : 0);
        _epoller->ModEvent(fd, events);
    }
    void Dispatcher(int timeout)
    {
        int n = _epoller->Wait(evs, _max_events, timeout);
        // 进行事件派发
        for(int i = 0; i < n; i++)
        {
            int fd = evs[i].data.fd;
            uint32_t events = evs[i].events;
            Connection *conn = nullptr;
            if(IsConnectionExists(fd))  
                conn = _connections[fd];
            // 若fd出错，给他添加读和写事件就绪，？/
            if(events & EPOLLERR)
                events |= (EPOLLIN | EPOLLOUT);
            if(IsConnectionExists(fd) && (events & EPOLLIN))
            {
                conn->_recver(conn);
            }
            if(IsConnectionExists(fd) && (events & EPOLLOUT))
                conn->_sender(conn);
        }
    }
    void Loop()
    {
        int timeout = _timeout;
        _isrunning = true;
        while(_isrunning)
        {
            Dispatcher(timeout);
        }
        _isrunning = false;
    }

private:
    Epoller *_epoller;
    int _max_events;
    struct epoll_event evs[64];
    std::unordered_map<int, Connection*> _connections;
    bool _isrunning;
    int _timeout;
};